﻿using System;
using SoftwareConsulting.BI11.Studio.InternalServices;
using SoftwareConsulting.BI11.NumericalMethods.MatrixAlgebra;

namespace SoftwareConsulting.BI11.NumericalMethods.Optimization
{
    /// <summary>
    /// Класс контроллера хромосом для хромосом - векторов
    /// </summary>
    public class VectorChromosomeController : ChromosomeController
    {
        private Vector[] _population;//популяция
        private int _currentPopulationSize;//текущий размер популяции
        private Vector _valuesOrigin;//начальная точка значений
        private Vector _valuesRange;//диапазон значений

        /// <summary>
        /// Конструктор класса
        /// </summary>
        public VectorChromosomeController() : 
            base()
        {
        }

        /// <summary>
        /// Конструктор класса
        /// </summary>
        /// <param name="populationSize">размер популяции</param>
        /// <param name="rateOfMutation">частота мутаций</param>
        /// <param name="rateOfCrossover">частота скрещиваний</param>
        public VectorChromosomeController(int populationSize, double rateOfMutation, double rateOfCrossover)
            : base(populationSize, rateOfMutation, rateOfCrossover)
        {
        }

        /// <summary>
        /// Добавляет клон указанного объекта
        /// </summary>
        /// <param name="originalObject"></param>
        public override void AddCloneOf(object originalObject)
        {
            double[] v = ((Vector)originalObject).CloneComponents();
            try 
            { 
                _population[_currentPopulationSize++] = new Vector(v); 
            }
            catch (OverflowException ex) 
            {
                Trace.StartBlock("OverflowException killed");
                Trace.Message("OverflowException catched and silently killed! Exception text:");
                Trace.Message(ex.ToString());
                Trace.EndBlock();
            };
        }

        /// <summary>
        /// Добавляет результат скрещивания указанных объектов
        /// </summary>
        /// <param name="fatherObject"></param>
        /// <param name="motherObject"></param>
        public override void AddCrossoversOf(object fatherObject, object motherObject)
        {
            double[] v = ((Vector)fatherObject).CloneComponents();
            double[] w = ((Vector)fatherObject).CloneComponents();
            int n = (int)(this.GetNextRandomDouble() * (_valuesOrigin.Dimensionality - 1));
            for (int i = 0; i < n; i++)
            {
                double temp = v[i];
                v[i] = w[i];
                w[i] = temp;
            }
            try
            {
                _population[_currentPopulationSize++] = new Vector(v);
                _population[_currentPopulationSize++] = new Vector(w);
            }
            catch (OverflowException ex) 
            {
                Trace.StartBlock("OverflowException killed");
                Trace.Message("OverflowException catched and silently killed! Exception text:");
                Trace.Message(ex.ToString());
                Trace.EndBlock();
            };
        }

        /// <summary>
        /// Добавляет результат мутации указанного объекта
        /// </summary>
        /// <param name="originalObject"></param>
        public override void AddMutationOf(object originalObject)
        {
            double[] v = ((Vector)originalObject).CloneComponents();
            int i = (int)(this.GetNextRandomDouble() * _valuesOrigin.Dimensionality);
            v[i] = GetNextRandomComponent(i);
            try 
            { 
                _population[_currentPopulationSize++] = new Vector(v); 
            }
            catch (OverflowException ex) 
            {
                Trace.StartBlock("OverflowException killed");
                Trace.Message("OverflowException catched and silently killed! Exception text:");
                Trace.Message(ex.ToString());
                Trace.EndBlock();
            };
        }

        /// <summary>
        /// Добавляет случайную хромосому
        /// </summary>
        public override void AddRandomChromosome()
        {
            double[] v = new double[_valuesOrigin.Dimensionality];
            for (int i = 0; i < _valuesOrigin.Dimensionality; i++)
                v[i] = GetNextRandomComponent(i);
            try 
            { 
                _population[_currentPopulationSize++] = new Vector(v); 
            }
            catch (OverflowException ex) 
            {
                Trace.StartBlock("OverflowException killed");
                Trace.Message("OverflowException catched and silently killed! Exception text:");
                Trace.Message(ex.ToString());
                Trace.EndBlock();
            };
        }

        /// <summary>
        /// Возвращает текущий размер популяции
        /// </summary>
        public override int CurrentPopulationSize
        {
            get { return _currentPopulationSize; }
        }

        /// <summary>
        /// Возвращает указанную особь
        /// </summary>
        /// <param name="individualIndex"></param>
        /// <returns></returns>
        public override object GetIndividualAt(int individualIndex)
        {
            return _population[individualIndex];
        }

        /// <summary>
        /// Возвращает случайное значение элемента
        /// </summary>
        /// <param name="componentIndex"></param>
        /// <returns></returns>
        private double GetNextRandomComponent(int componentIndex)
        {
            return _valuesOrigin[componentIndex] + this.GetNextRandomDouble() * _valuesRange[componentIndex];
        }

        /// <summary>
        /// Сбрасывает популяцию
        /// </summary>
        public override void Reset()
        {
            _population = new Vector[this.DesiredPopulationSize];
            _currentPopulationSize = 0;
        }

        /// <summary>
        /// Устанавливает начальную точку значений
        /// </summary>
        /// <param name="originComponents">Элементы начальной точки гиперкуба домена оптимизируемой функции</param>
        public void SetOrigin(double[] originComponents)
        {
            this._valuesOrigin = new Vector(originComponents);
        }

        /// <summary>
        /// Возвращает/устанавливает начальную точку значений
        /// </summary>
        public Vector Origin
        {
            get
            {
                return _valuesOrigin;
            }
            set 
            { 
                _valuesOrigin = value; 
            }
        }

        /// <summary>
        /// Устанавливает диапазон значений
        /// </summary>
        /// <param name="lengthComponents">Элементы длин граней гиперкуба домена оптимизируемой функции</param>
        public void SetRange(double[] lengthComponents)
        {
            this.Range = new Vector(lengthComponents);
        }

        /// <summary>
        /// Возвращает/устанавливает диапазон значений
        /// </summary>
        public Vector Range
        {
            get
            {
                return _valuesRange;
            }
            set 
            { 
                _valuesRange = value; 
            }
        }
    }
}
